﻿//ContinuousSecurityWindow.xaml.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Xaml
{
	using System;
	using System.Collections.Generic;
	using System.Collections.ObjectModel;
	using System.IO;
	using System.Linq;
	using System.Windows;
	using System.Windows.Controls;

	using Ecng.Xaml;
	using Ecng.Common;
	using Ecng.Collections;

	using StockSharp.Algo;
	using StockSharp.BusinessEntities;

	/// <summary>
	/// Окно для создания или редактирования <see cref="ContinuousSecurity"/>.
	/// </summary>
	public partial class ContinuousSecurityWindow
	{
		private sealed class Jump
		{
			private Security _security;

			public Security Security
			{
				get { return _security; }
				set
				{
					if (Security == value)
						return;

					_security = value;
					Changed.SafeInvoke();
				}
			}

			private string _date;

			public string Date
			{
				get { return _date; }
				set
				{
					if (Date == value)
						return;

					_date = value;
					Changed.SafeInvoke();
				}
			}

			public event Action Changed;
		}

		private readonly ObservableCollection<Jump> _jumps = new ObservableCollection<Jump>(); 

		/// <summary>
		/// Создать <see cref="ContinuousSecurityWindow"/>.
		/// </summary>
		public ContinuousSecurityWindow()
		{
			InitializeComponent();
			JumpsGrid.ItemsSource = _jumps;

			_continuousSecurity = new ContinuousSecurity
			{
				ExtensionInfo = new Dictionary<object, object>()
			};
		}

		private Func<string, bool> _validateId = id => true;

		/// <summary>
		/// Обработчик, проверяющий доступность введенного идентификатора для <see cref="ContinuousSecurity"/>.
		/// </summary>
		public Func<string, bool> ValidateId
		{
			get { return _validateId; }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				_validateId = value;
			}
		}

		private ContinuousSecurity _continuousSecurity;

		/// <summary>
		/// Непрерывный инструмент.
		/// </summary>
		public ContinuousSecurity ContinuousSecurity
		{
			get { return _continuousSecurity; }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				_continuousSecurity = value;

				SecurityId.Text = value.Id;

				_jumps.AddRange(value.ExpirationJumps.Select(p => Subscribe(new Jump
				{
					Security = p.Key,
					Date = p.Value.To<string>()
				})));

				Title += value.Id;
			}
		}

		private Jump SelectedJump
		{
			get { return (Jump)JumpsGrid.SelectedItem; }
		}

		private void AddRow_Click(object sender, RoutedEventArgs e)
		{
			_jumps.Add(Subscribe(new Jump()));
			EnableSave();
		}

		private void RemoveRow_Click(object sender, RoutedEventArgs e)
		{
			_jumps.Remove(UnSubscribe(SelectedJump));
			EnableSave();
		}

		private Jump Subscribe(Jump jump)
		{
			if (jump == null)
				throw new ArgumentNullException("jump");

			jump.Changed += OnJumpChanged;
			return jump;
		}

		private Jump UnSubscribe(Jump jump)
		{
			if (jump == null)
				throw new ArgumentNullException("jump");

			jump.Changed -= OnJumpChanged;
			return jump;
		}

		private void OnJumpChanged()
		{
			EnableSave();
		}

		private void OK_Click(object sender, RoutedEventArgs e)
		{
			var mbBuilder = new MessageBoxBuilder()
				.Owner(this)
				.Error();

			if (_jumps.Any(j => j.Security == null))
			{
				mbBuilder.Text("Некоторые инструменты не заполнены.").Show();
				return;
			}

			if (_jumps.Any(j => j.Security is BasketSecurity))
			{
				mbBuilder.Text("Некоторые инструменты являются составными.").Show();
				return;
			}

			if (_jumps.Any(j => j.Date == null))
			{
				mbBuilder.Text("Некоторые даты не заполнены.").Show();
				return;
			}

			if (_jumps.GroupBy(j => j.Security).Any(g => g.Count() > 1))
			{
				mbBuilder.Text("Некоторые инструменты дублируются.").Show();
				return;
			}

			if (_jumps.GroupBy(j => j.Date).Any(g => g.Count() > 1))
			{
				mbBuilder.Text("Некоторые даты дублируются.").Show();
				return;
			}

			if (_continuousSecurity.Id.IsEmpty())
			{
				var id = SecurityId.Text.Trim();

				if (!_validateId(id))
				{
					mbBuilder.Text("Инструмент с идентификатором {0} уже существует.".Put(id)).Show();
					return;
				}

				if (Path.GetInvalidFileNameChars().Any(id.Contains))
				{
					mbBuilder.Text("'{0}' является недопустимым идентификатором. Символы '{1}' являются недопустимыми.".Put(id, Path.GetInvalidFileNameChars().Select(c => c.ToString()).Join(", "))).Show();
					return;
				}

				_continuousSecurity.Id = SecurityId.Text;

				var underlyingSecurity = _jumps[0].Security;
				_continuousSecurity.ExchangeBoard = underlyingSecurity.ExchangeBoard;
				_continuousSecurity.MinStepSize = underlyingSecurity.MinStepSize;
				_continuousSecurity.Type = underlyingSecurity.Type;
				_continuousSecurity.Trader = underlyingSecurity.Trader;
			}

			_continuousSecurity.ExpirationJumps.Clear();
			_continuousSecurity.ExpirationJumps.AddRange(_jumps.Select(j => new KeyValuePair<Security, DateTime>(UnSubscribe(j).Security, j.Date.To<DateTime>())));

			DialogResult = true;
			Close();
		}

		private void SecurityId_TextChanged(object sender, TextChangedEventArgs e)
		{
			EnableSave();
			Auto.IsEnabled = !SecurityId.Text.IsEmpty();
		}

		private void EnableSave()
		{
			OK.IsEnabled = !SecurityId.Text.IsEmpty() && !_jumps.IsEmpty();
		}

		private void JumpsGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			RemoveRow.IsEnabled = SelectedJump != null;
		}

		private void Auto_Click(object sender, RoutedEventArgs e)
		{
			var newSecurities = ContinuousSecurity.GetFortsJumps(SecurityId.Text, DateTime.Today - TimeSpan.FromTicks(TimeSpanHelper.TicksPerYear * 10), DateTime.Today, false);

			if (!newSecurities.IsEmpty())
			{
				_jumps.ForEach(j => UnSubscribe(j));
				_jumps.Clear();
				_jumps.AddRange(newSecurities.Select(s => Subscribe(new Jump
				{
					Security = s,
					Date = s.ExpiryDate != null ? s.ExpiryDate.ToString() : string.Empty
				})));

				new MessageBoxBuilder()
					.Owner(this)
					.Text("Непрерывный фьючерс перестроен.")
						.Show();
			}
			else
			{
				new MessageBoxBuilder()
					.Owner(this)
					.Error()
					.Text("Недостаточно данных для автоматического построения непрерывного фьючерса.")
						.Show();
			}
		}
	}
}